<?php
/**
 * 用户行为处理类
 * 必须依赖MyPDO类、Session功能，可选依赖MyLog类
 * @author FLY
 *
 */
class MemberHelper
{
    static $password_key = '9B389856B627CF58F77E2F02C3695DD0';
    static $remember_time = 2592000; // 30天
    static $remember_key = '8C4595AD299C1EED9C34C67F5F846290';
    static $error_interval = 10800; // 允许密码错误间隔：3小时
    static $error_times = 5; // 允许密码错误次数，超过则拒绝登陆
    static $csrf_key = 'CA969A1BC97732D97B1E88CE8396C216';
    static function login($uid, $password, $type = 0, $is_remember = false)
    {
        // 开启会话
        if (session_status() !== PHP_SESSION_ACTIVE)
        {
            session_start();
        }
        
        $db = MyPDO::get_instance();
        
        // 获取用户
        $member = self::get_member( $uid, $type );
        if (empty( $member ))
        {
            // return '用户名错误';
            return '用户名或密码错误';
        }
        
        // 用户登陆错误次数
        $db->select( 'member_login', 'count(*)', '`uid`=? and `add_time`>? and `is_passed`=0', array (
                $member['id'],
                $_SERVER['REQUEST_TIME'] - self::$error_interval 
        ) );
        $error_count = ( int ) $db->fetch_cell();
        if ($error_count >= self::$error_times)
        {
            return '拒绝登陆！您在' . round( self::$error_interval / 3600 ) . '小时内已超过' . self::$error_times . '次错误';
        }
        
        // 关联请求id
        $request_id = 0;
        if (class_exists( 'MyLog', false ))
        {
            $request_id = MyLog::get_instance()->get_request_id();
        }
        
        // 验证密码
        $password = self::encrypt_password( $password );
        // echo $password;
        if ($member['password'] !== $password)
        {
            // 记录本次登陆信息：登陆失败
            $db->insert( 'member_login', array (
                    'uid' => $member['id'],
                    'is_passed' => 0,
                    'ip' => isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : null,
                    'add_time' => $_SERVER['REQUEST_TIME'],
                    'request_id' => $request_id 
            ) )->execute();
            // return '密码错误';
            return '用户名或密码错误';
        }
        
        // 重新生成session_id，防止固定session攻击，并且删除旧的会话
        session_regenerate_id( true );
        // session中记录
        $_SESSION['member'] = $member;
        
        // 将用户关联到日志
        if (class_exists( 'MyLog', false ))
        {
            MyLog::get_instance()->set_user( $member['id'] );
        }
        
        // 记住登陆
        if ($is_remember)
        {
            $token = $_SERVER['REQUEST_TIME_FLOAT'];
            $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
            $signature = sha1( self::$remember_key . $member['id'] . $token . $user_agent );
            if (! empty( $_COOKIE['MEMBER_SIGNATURE'] ))
            {
                $db->update( 'member_login', array (
                        'signature_expire' => 0 
                ), '`signature`=?', $_COOKIE['MEMBER_SIGNATURE'] )->execute();
            }
            setcookie( 'MEMBER_TOKEN', $token, $_SERVER['REQUEST_TIME'] + self::$remember_time, '/' );
            setcookie( 'MEMBER_SIGNATURE', $signature, $_SERVER['REQUEST_TIME'] + self::$remember_time, '/' );
        }
        
        // 记录本次登陆信息：登陆成功
        $db->insert( 'member_login', array (
                'uid' => $member['id'],
                'is_passed' => 1,
                'ip' => isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : null,
                'add_time' => $_SERVER['REQUEST_TIME'],
                'request_id' => $request_id,
                'signature' => isset( $signature ) ? $signature : null,
                'signature_expire' => $_SERVER['REQUEST_TIME'] + self::$remember_time 
        ) )->execute();
        
        return true;
    }
    static function check_login($auto_login = true)
    {
        // 开启会话
        if (session_status() !== PHP_SESSION_ACTIVE)
        {
            session_start();
        }
        if (isset( $_SESSION['member'] ))
        {
            // 将用户关联到日志
            if (class_exists( 'MyLog', false ))
            {
                MyLog::get_instance()->set_user( $_SESSION['member']['id'] );
            }
            return true;
        }
        if ($auto_login)
        {
            // 验证签名
            if (empty( $_COOKIE['MEMBER_TOKEN'] ) || empty( $_COOKIE['MEMBER_SIGNATURE'] ))
            {
                return false;
            }
            $token = $_COOKIE['MEMBER_TOKEN'];
            $signature = $_COOKIE['MEMBER_SIGNATURE'];
            $db = MyPDO::get_instance();
            $db->select( 'member_login', 'uid', 'signature=? and `signature_expire`>?', array (
                    $signature,
                    $_SERVER['REQUEST_TIME'] 
            ) );
            $db->limit( 1 );
            $login_info = $db->fetch_row();
            if (empty( $login_info ))
            {
                return false;
            }
            $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
            if ($signature !== sha1( self::$remember_key . $login_info['uid'] . $token . $user_agent ))
            {
                return false;
            }
            // 获取用户
            $member = self::get_member( $login_info['uid'] );
            if (empty( $member ))
            {
                return false;
            }
            // 重新生成session_id，防止固定session攻击
            session_regenerate_id( true );
            // session中记录
            $_SESSION['member'] = $member;
            
            // 将用户关联到日志
            if (class_exists( 'MyLog', false ))
            {
                MyLog::get_instance()->set_user( $member['id'] );
            }
            
            return true;
        }
        return false;
    }
    static function logout()
    {
        // 开启会话
        if (session_status() !== PHP_SESSION_ACTIVE)
        {
            session_start();
        }
        unset( $_SESSION['member'] );
        if (! empty( $_COOKIE['MEMBER_SIGNATURE'] ))
        {
            MyPDO::get_instance()->update( 'member_login', array (
                    'signature_expire' => 0 
            ), '`signature`=?', $_COOKIE['MEMBER_SIGNATURE'] )->execute();
        }
        setcookie( 'MEMBER_TOKEN', '', strtotime( '-1 day' ), '/' );
        setcookie( 'MEMBER_SIGNATURE', '', strtotime( '-1 day' ), '/' );
        return true;
    }
    static function check_member($username, $type = 1)
    {
        switch (( int ) $type)
        {
            case 2 :
                $field = 'mobile';
                break;
            case 3 :
                $field = 'email';
                break;
            default :
                $field = 'username';
        }
        $db = MyPDO::get_instance();
        $db->select( 'member', '*', "`$field`=?", $username );
        $db->limit( 1 );
        return $db->fetch_cell();
    }
    static function modify_password($uid, $old_password, $new_password)
    {
        $old_password = self::encrypt_password( $old_password );
        $new_password = self::encrypt_password( $new_password );
        
        $db = MyPDO::get_instance();
        $db->update( 'member', array (
                'password' => $new_password 
        ) );
        $db->where( '`id`=? and `password`=?', array (
                $uid,
                $old_password 
        ) );
        return $db->affected_rows();
    }
    static function get_member($uid, $type = 0)
    {
        switch (( int ) $type)
        {
            case 1 :
                $field = 'username';
                break;
            case 2 :
                $field = 'mobile';
                break;
            case 3 :
                $field = 'email';
                break;
            default :
                $field = 'id';
        }
        // 获取用户
        $db = MyPDO::get_instance();
        $db->select( 'member', '*', "`$field`=? and `deleted`=0 and `enable`=1", $uid );
        $db->limit( 1 );
        $member = $db->fetch_row();
        if (empty( $member ))
        {
            return false;
        }
        // 上次登陆信息
        $db->select( 'member_login', '`ip` as `last_ip`,`add_time` as `last_time`' );
        $db->where( '`uid`=? and `is_passed`=1', $member['id'] );
        $db->order( 'add_time desc' );
        $db->limit( 1 );
        $history = $db->fetch_row();
        if (is_array( $history ) && ! empty( $history ))
        {
            $member += $history;
        }
        else
        {
            $member['last_ip'] = null;
            $member['last_time'] = null;
        }
        $member['CSRF'] = md5( self::$csrf_key . $member['id'] . $_SERVER['REQUEST_TIME_FLOAT'] );
        return $member;
    }
    static function encrypt_password($password)
    {
        return sha1( self::$password_key . $password );
    }
    static function clean($uid)
    {
        $db = MyPDO::get_instance();
        $db->delete( 'member_login', 'add_time<? or uid=?', array (
                $_SERVER['REQUEST_TIME'] - self::$remember_time,
                $uid 
        ) );
        return $db->execute();
    }
}